From: mjw@wray-m-3.hpl.hp.com Date: Tue, 21 Sep 2004 14:29:16 +0000 (+0000) Subject: bitkeeper revision 1.1159.1.164 (41503abcmVn6L0phzf-BOxlxa3zgxw) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~17400^2~587 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=a23e4c0121b63cb891005234a88d59f497d0f72c;p=xen.git bitkeeper revision 1.1159.1.164 (41503abcmVn6L0phzf-BOxlxa3zgxw) Add support for reconfiguring an existing device, including support for changing the bridge of a vif. Treat bridge "null" as meaning no bridge. --- diff --git a/tools/examples/network b/tools/examples/network index 6574399089..b679b93e43 100755 --- a/tools/examples/network +++ b/tools/examples/network @@ -139,31 +139,44 @@ show_status () { echo '============================================================' } +op_start () { + if [ "${bridge}" == "null" ] ; then + return + fi + # Create the bridge and give it the interface IP addresses. + # Move the interface routes onto the bridge. + create_bridge ${netdev} ${bridge} + transfer_addrs ${netdev} ${bridge} + transfer_routes ${netdev} ${bridge} + # Don't add $dev to $bridge if it's already on a bridge. + if ! brctl show | grep -q ${netdev} ; then + brctl addif ${bridge} ${netdev} + fi + + if [ ${antispoof} == 'yes' ] ; then + antispoofing ${netdev} ${bridge} + fi +} + +op_stop () { + if [ "${bridge}" == "null" ] ; then + return + fi + # Remove the interface from the bridge. + # Move the routes back to the interface. + brctl delif ${bridge} ${netdev} + transfer_routes ${bridge} ${netdev} + + # It's not our place to be enabling forwarding... +} + case ${OP} in start) - # Create the bridge and give it the interface IP addresses. - # Move the interface routes onto the bridge. - create_bridge ${netdev} ${bridge} - transfer_addrs ${netdev} ${bridge} - transfer_routes ${netdev} ${bridge} - # Don't add $dev to $bridge if it's already on a bridge. - if ! brctl show | grep -q ${netdev} ; then - brctl addif ${bridge} ${netdev} - fi - - if [ ${antispoof} == 'yes' ] ; then - antispoofing ${netdev} ${bridge} - fi - + op_start ;; stop) - # Remove the interface from the bridge. - # Move the routes back to the interface. - brctl delif ${bridge} ${netdev} - transfer_routes ${bridge} ${netdev} - - # It's not our place to be enabling forwarding... + op_stop ;; status) diff --git a/tools/examples/vif-bridge b/tools/examples/vif-bridge index 2138aa7b94..505ac1ec51 100755 --- a/tools/examples/vif-bridge +++ b/tools/examples/vif-bridge @@ -69,6 +69,11 @@ case $OP in ;; esac +# Don't do anything if the bridge is "null". +if [ "${bridge}" == "null" ] ; then + exit +fi + # Add/remove vif to/from bridge. brctl ${brcmd} ${bridge} ${vif} diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 01d6d3df3c..958742d168 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -550,6 +550,12 @@ class Xend: 'type' : type, 'idx' : idx }) + def xend_domain_device_configure(self, id, config, idx): + return self.xendPost(self.domainurl(id), + {'op' : 'device_configure', + 'idx' : idx, + 'config' : fileof(config) }) + def xend_consoles(self): return self.xendGet(self.consoleurl()) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index afe2a4601b..8aa33484f1 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -684,12 +684,27 @@ class XendDomain: self.update_domain(dominfo.id) return val + def domain_device_configure(self, id, devconfig, idx): + """Configure an existing device for a domain. + + @param id: domain id + @param devconfig: device configuration + @param idx: device index + @return: updated device configuration + """ + dominfo = self.domain_lookup(id) + self.refresh_schedule() + val = dominfo.device_configure(devconfig, idx) + self.update_domain(dominfo.id) + return val + + def domain_device_destroy(self, id, type, idx): """Destroy a device. @param id: domain id - @param type: device type @param idx: device index + @param type: device type """ dominfo = self.domain_lookup(id) self.refresh_schedule() @@ -706,7 +721,6 @@ class XendDomain: """ dominfo = self.domain_lookup(id) devs = dominfo.get_devices(type) - #return range(0, len(devs)) return devs def domain_devtype_get(self, id, type, idx): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index f582a51145..17a002c665 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -825,6 +825,30 @@ class XendDomainInfo: d = dev_handler(self, dev_config, dev_index, change=1) return d + def device_configure(self, dev_config, idx): + """Configure an existing device. + + @param dev_config: device configuration + @param idx: device index + """ + type = sxp.name(dev_config) + dev = self.get_device_by_index(type, idx) + if not dev: + raise VmError('invalid device: %s %s' % (type, idx)) + new_config = dev.configure(dev_config, change=1) + devs = self.devices.get(type) + index = devs.index(dev) + # Patch new config into device configs. + dev_configs = self.config_devices(type) + old_config = dev_configs[index] + dev_configs[index] = new_config + # Patch new config into vm config. + new_full_config = ['device', new_config] + old_full_config = ['device', old_config] + old_index = self.config.index(old_full_config) + self.config[old_index] = new_full_config + return new_config + def device_destroy(self, type, idx): """Destroy a device. diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index bdd57524ce..a0ec17526f 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -164,6 +164,14 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.id}) return val + def op_device_configure(self, op, req): + fn = FormFn(self.xd.domain_device_configure, + [['dom', 'str'], + ['config', 'sxpr'], + ['idx', 'str']]) + d = fn(req.args, {'dom': self.dom.id}) + return d + def op_vifs(self, op, req): devs = self.xd.domain_vif_ls(self.dom.id) return [ dev.sxpr() for dev in devs ] diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index d77f51c10c..71855d8755 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -617,6 +617,9 @@ class Dev: """ raise NotImplementedError() + def configure(self, config, change=0): + raise NotImplementedError() + class SplitDev(Dev): def __init__(self, idx, controller): diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 3c07333a84..84f569d830 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -104,31 +104,82 @@ class NetDev(controller.SplitDev): self.evtchn = None self.configure(config) - def configure(self, config): + def _get_config_mac(self, config): + vmac = sxp.child_value(config, 'mac') + if not vmac: return None + mac = [ int(x, 16) for x in vmac.split(':') ] + if len(mac) != 6: raise XendError("invalid mac") + return mac + + def _get_config_ipaddr(self, config): + ips = sxp.children(config, elt='ip') + if ips: + val = [] + for ipaddr in ips: + val.append(sxp.child0(ipaddr)) + else: + val = None + return val + + def configure(self, config, change=0): + if change: + return self.reconfigure(config) self.config = config self.mac = None self.bridge = None self.script = None self.ipaddr = [] - - vmac = sxp.child_value(config, 'mac') - if not vmac: raise XendError("invalid mac") - mac = [ int(x, 16) for x in vmac.split(':') ] - if len(mac) != 6: raise XendError("invalid mac") - self.mac = mac + mac = self._get_config_mac(config) + if mac is None: + raise XendError("invalid mac") + self.mac = mac self.bridge = sxp.child_value(config, 'bridge') self.script = sxp.child_value(config, 'script') - - ipaddrs = sxp.children(config, elt='ip') - for ipaddr in ipaddrs: - self.ipaddr.append(sxp.child0(ipaddr)) + self.ipaddr = self._get_config_ipaddr(config) or [] try: self.backendDomain = int(sxp.child_value(config, 'backend', '0')) except: raise XendError('invalid backend domain') + def reconfigure(self, config): + """Reconfigure the interface with new values. + Not all configuration parameters can be changed: + bridge, script and ip addresses can, + backend and mac cannot. + + To leave a parameter unchanged, omit it from the changes. + + @param config configuration changes + @return updated interface configuration + @raise XendError on errors + """ + changes = {} + mac = self._get_config_mac(config) + bridge = sxp.child_value(config, 'bridge') + script = sxp.child_value(config, 'script') + ipaddr = self._get_config_ipaddr(config) + backendDomain = sxp.child_value(config, 'backend', '0') + if (mac is not None) and (mac != self.mac): + raise XendError("cannot change mac") + if (backendDomain is not None) and (backendDomain != str(self.backendDomain)): + raise XendError("cannot change backend") + if (bridge is not None) and (bridge != self.bridge): + changes['bridge'] = bridge + if (script is not None) and (script != self.script): + changes['script'] = script + if (ipaddr is not None) and (ipaddr != self.ipaddr): + changes['ipaddr'] = ipaddr + + if changes: + self.vifctl("down") + for (k, v) in changes.items(): + setattr(self, k, v) + self.config = sxp.merge(config, self.config) + self.vifctl("up") + return self.config + def sxpr(self): vif = str(self.vif) mac = self.get_mac() diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py index 4fd9e9a92b..98cc303416 100644 --- a/tools/python/xen/xend/sxp.py +++ b/tools/python/xen/xend/sxp.py @@ -41,7 +41,8 @@ __all__ = [ "has_id", "with_id", "child_with_id", - "elements", + "elements", + "merge", "to_string", "from_string", "all_from_string", @@ -595,6 +596,77 @@ def elements(sxpr, ctxt=None): yield v i += 1 +def merge(s1, s2): + """Merge sxprs s1 and s2. + Returns an sxpr containing all the fields from s1 and s2, with + entries in s1 overriding s2. Recursively merges fields. + + @param s1 sxpr + @param s2 sxpr + @return merged sxpr + """ + if s1 is None: + val = s2 + elif s2 is None: + val = s1 + elif elementp(s1): + name1 = name(s1) + (m1, v1) = child_map(s1) + (m2, v2) = child_map(s2) + val = [name1] + for (k1, f1) in m1.items(): + merge_list(val, f1, m2.get(k1, [])) + for (k2, f2) in m2.items(): + if k2 in m1: continue + val.extend(f2) + val.extend(v1) + else: + val = s1 + return val + +def merge_list(sxpr, l1, l2): + """Merge element lists l1 and l2 into sxpr. + The lists l1 and l2 are all element with the same name. + Values from l1 are merged with values in l2 and stored in sxpr. + If one list is longer than the other the excess values are used + as they are. + + @param sxpr to merge into + @param l1 sxpr list + @param l2 sxpr list + @return modified sxpr + """ + n1 = len(l1) + n2 = len(l2) + nmin = min(n1, n2) + for i in range(0, nmin): + sxpr.append(merge(l1[i], l2[i])) + for i in range(nmin, n1): + sxpr.append(l1[i]) + for i in range(nmin, n2): + sxpr.append(l2[i]) + return sxpr + +def child_map(sxpr): + """Get a dict of the elements in sxpr and a list of its values. + The dict maps element name to the list of elements with that name, + and the list is the non-element children. + + @param sxpr + @return (dict, list) + """ + m = {} + v = [] + for x in children(sxpr): + if elementp(x): + n = name(x) + l = m.get(n, []) + l.append(x) + m[n] = l + else: + v.append(x) + return (m, v) + def to_string(sxpr): """Convert an sxpr to a string.